home *** CD-ROM | disk | FTP | other *** search
- \foot4
- \ctr\- \%page\ -
- \right
- 605057
- \left
- \lm0
- \rm80
- \hy
- \ssa
- \ssb
- \bf
- \un
- name emsdisk
- page 55,132
- title EMSDISK for Expanded Memory
-
- ; EMSDISK for Lotus/Intel/Microsoft Expanded Memory
- ;
- ; Copyright (C) 1986 Ray Duncan
- ; version 1.0 May 1986
- ;
- ; This program may be freely reproduced and modified for
- ; non-commercial (personal) use. It may not be resold or
- ; incorporated into products for resale without written
- ; permission from the author.
- ;
- ; To convert EMSDISK.ASM into the executable EMSDISK.BIN:
- ; C>MASM EMSDISK;
- ; C>LINK EMSDISK;
- ; C>EXE2BIN EMSDISK.EXE EMSDISK.BIN
- ; C>DEL EMSDISK.EXE
- ;
- ; To link the EMSDISK into the MS-DOS operating system,
- ; copy the EMSDISK.BIN file to your boot disk and add the line:
- ;
- ; DEVICE=EMSDISK.BIN nnnK
- ;
- ; into the CONFIG.SYS file on your boot disk (where nnnK is the
- ; desired EMSDISK size in Kbytes) AFTER the line that loads
- ; the Expanded Memory Manager (EMM.SYS for Intel Above Board).
- ;
-
- code segment public 'CODE'
-
- assume cs:code,ds:code,es:code
-
- org 0
-
- cc2_max equ 12 ; max driver command code for DOS 2
- cc3_max equ 16 ; max driver command code for DOS 3
-
- cr equ 0dh ; ASCII carriage return
- lf equ 0ah ; ASCII line feed
- blank equ 020h ; ASCII space code
- eom equ '$' ; end of message signal
-
- emm_int equ 67h ; Software Interrupt for communication
- ; with Expanded Memory Manager
-
- page_size equ 16384 ; bytes per logical EMS page
-
- sec_size equ 512 ; bytes per logical sector, should
- ; be some multiple of 512 <= 16384.
-
- dir_size equ 256 ; entries in root directory
-
- ; logical sectors per EMS page
- sec_per_page equ page_size/sec_size
-
- page
-
- ; MS-DOS Request Header structure definition
-
- request struc ; request header template structure
- ; beginning of "Static" portion
- rlength db ? ; length of request header
- unit db ? ; unit number for this request
- command db ? ; request header's command code
- status dw ? ; driver's return status word
- ; bit 15 = Error
- ; bits 10-14 = Reserved
- ; bit 9 = Busy
- ; bit 8 = Done
- ; bits 0-7 = Error code if bit 15=1
- reserve db 8 dup (?) ; reserved area
- ; end of "Static" portion, the remainder
- ; is struc. for Read and Write commands
- media db ? ; media descriptor byte
- address dd ? ; memory address for transfer
- count dw ? ; byte/sector count value
- sector dw ? ; starting sector value
- request ends ; end of request header template
-
- page
-
- ;
- ; Device Driver header
- ;
- header dd -1 ; link to next device driver in chain
- dw 0 ; device attribute word
- ; bit 15 =1 for character devices
- ; =0 for block devices
- ; bit 14 =1 if driver can handle IOCTL
- ; bit 13 =1 if block device & non-IBM format
- ; bit 12 reserved
- ; bit 11 =1 if OPEN/CLOSE/RM supported (DOS 3)
- ; bits 4-10 reserved
- ; bit 3 =1 if CLOCK device
- ; bit 2 =1 if NUL device
- ; bit 1 =1 if Standard Output
- ; bit 0 =1 if Standard Input
- dw strat ; device "Strategy" entry point
- dw intr ; device "Interrupt" entry point
- db 1 ; number of units, this device
- db 7 dup (0) ; reserved area (block dev. drivers)
-
- rh_ptr dd ? ; double word pointer to Request header
-
- save_sp dw 0 ; save DOS's SS:SP
- save_ss dw 0
-
- avail_pages dw 0 ; logical EMS pages available
- total_pages dw 0 ; total logical EMS pages in system
- req_pages dw 0 ; EMSDISK requested size in EMS pages
- owned_pages dw 0 ; logical EMS pages owned by EMSDISK
- page_frame dw 0 ; segment address of page frame
- emm_handle dw 0 ; EMSDISK EMM handle (process id)
-
- dos_ver db 0 ; DOS major version no.
- max_cmd dw 0 ; maximum command code, this DOS version
-
- xfer_sec dw 0 ; current sector for transfer
- xfer_cnt dw 0 ; sectors successfully transferred
- xfer_req dw 0 ; number of sectors requested
- xfer_addr dd 0 ; working address for transfer
-
- bpb_array dw bpb ; array of pointers to BPB for each unit
-
- ; copy of CONFIG.SYS line for driver
- cmd_line db 80 dup (0)
-
- even ; force word alignment
- dw 128 dup (0)
- stk equ $ ; local stack for use by driver
-
- page
-
- boot_rec equ $
-
- jmp $ ; phony JMP at start of
- nop ; boot sector, this field
- ; must be 3 bytes.
-
- db 'EMRAMDSK' ; OEM identity field
-
- ; BIOS Parameter Block (BPB).
- ; "sectors per cluster", "total
- ; sectors" & "sectors per FAT"
- ; are updated by "setup" procedure
- bpb dw sec_size ; 0 bytes per sector
- sec_clus db 0 ; 2 sectors per cluster
- dw 1 ; 3 reserved sectors
- db 1 ; 5 number of FATs
- dw dir_size ; 6 root directory entries
- tot_sec dw 0 ; 8 total sectors
- db 0f8h ; 0AH media descriptor
- sec_fat dw 0 ; 0BH sectors per FAT
-
- boot_rec_len equ $-boot_rec ; length to copy to
- ; EMSDISK logical sector 0
-
-
- page
-
- ; EMSDISK Device Driver "Strategy Routine"
- ;
- ; Each time a request is made for the logical unit assigned
- ; to the EMSDISK, MS-DOS first calls the "Strategy Routine",
- ; then immediately calls the "Interrupt Routine".
- ;
- ; The Strategy Routine is passed the address of the
- ; Request header in ES:BX, which it saves in a local
- ; variable and then returns to MS-DOS.
-
- strat proc far
- ; save address of Request header
- mov word ptr cs:[rh_ptr],bx
- mov word ptr cs:[rh_ptr+2],es
-
- ret ; back to MS-DOS
-
- strat endp
-
- page
-
-
- ; EMSDISK Device Driver "Interrupt Routine"
- ;
- ; This entry point is called by MS-DOS immediately after
- ; the call to the "Strategy Routine", which saved the long
- ; address of the Request header in the local variable "rh_ptr".
-
- ; The "Interrupt Routine" uses the Command Code passed in
- ; the Request header to transfer to the appropriate device
- ; handling routine. Each Command Code subroutine returns
- ; with AX=status.
-
- intr proc far
-
- push ax ; save general registers
- push bx
- push cx
- push dx
- push ds
- push es
- push di
- push si
- push bp
-
- mov ax,cs ; make local data addressable
- mov ds,ax
-
- mov save_ss,ss ; save DOS's stack pointers
- mov save_sp,sp
-
- mov ss,ax ; set SS:SP to point to
- mov sp,offset stk ; (larger) local stack
-
- les di,[rh_ptr] ; let ES:DI = Request header
-
- ; get BX = command Code
- mov bl,es:[di.command]
- xor bh,bh
- cmp bx,max_cmd ; make sure it's legal
- jle intr1 ; jump, function code is ok
- mov ax,8003h ; set Error bit and "Unknown command" code
- jmp intr3
-
- intr1: or bx,bx ; is it init call? (function 0)
- jz intr2 ; yes, skip save of context
-
- mov ah,47h ; save EMM page map for
- mov dx,emm_handle ; the interrupted process
- int 67h
-
- or ah,ah ; jump if EMM error while
- jnz intr9 ; saving page mapping context
-
- intr2: shl bx,1 ; form index to dispatch table and
- ; branch to command code routine
- call word ptr [bx+dispatch]
- ; should return AX = status
-
- les di,[rh_ptr] ; restore ES:DI = addr of Request header
-
- intr3: or ax,0100h ; merge Done bit into status, and
- ; store into Request header
- mov es:[di.status],ax
-
- ; Was this initialization call?
- mov bl,es:[di.command]
- or bl,bl
- jz intr4 ; yes, skip restore of context
-
- mov ah,48h ; restore EMM page map
- mov dx,emm_handle ; for interrupted process
- int 67h
-
- or ah,ah ; jump if EMM error while
- jnz intr9 ; restoring page mapping
-
- intr4: ; central exit point from
- ; driver's "INTR" routine
-
- mov ss,save_ss ; restore DOS's stack
- mov sp,save_sp
-
- pop bp ; restore general registers
- pop si
- pop di
- pop es
- pop ds
- pop dx
- pop cx
- pop bx
- pop ax
- ret ; back to MS-DOS
-
- intr9: ; come here if disastrous EMM error
- ; encountered to set "General Failure"
- ; error code and return to MS-DOS
-
- les di,[rh_ptr] ; ES:DI = addr of Request header
-
- ; Set Error bit, Done bit, and
- ; Error Code 12 (0CH)
- mov es:[di.status],810ch
- jmp intr4
-
- intr endp
-
-
- ; MS-DOS Command Codes dispatch table. The "Interrupt" routine uses
- ; this table and the Command Code supplied in the Request Header to
- ; transfer to the appropriate driver subroutine. Table entries for
- ; command codes not supported by this driver point to a dummy routine
- ; that only sets the "done" status and exits.
-
- dispatch:
- dw init ; 0 = initialize driver
- dw media_chk ; 1 = media check on block device
- dw build_bpb ; 2 = build BIOS parameter block
- dw dummy ; 3 = I/O control read
- dw read ; 4 = read from device
- dw dummy ; 5 = non-destructive read
- dw dummy ; 6 = return current input status
- dw dummy ; 7 = flush device input buffers
- dw write ; 8 = write to device
- dw write ; 9 = write with verify
- dw dummy ; 10 = return current output status
- dw dummy ; 11 = flush output buffers
- dw dummy ; 12 = I/O control write
- dw dummy ; 13 = device open (DOS 3.X)
- dw dummy ; 14 = device close (DOS 3.X)
- dw dummy ; 15 = removeable media (DOS 3.X)
- dw dummy ; 16 = output until busy (DOS 3.X)
-
- page
-
- ;
- ; Command Code subroutines called by Interrupt Routine
- ;
- ; These routines are called with ES:DI = Request Header.
- ;
- ; They should return AX = 0 if function was completed
- ; successfully, or AX = 8000H + Error code if function failed.
- ;
-
- media_chk proc near ; command code 1 = Media Check
-
- ; return "not changed" code
- mov byte ptr es:[di+14],1
-
- xor ax,ax ; set "done" status
- ret
-
- media_chk endp
-
-
- build_bpb proc near ; command code 2 = Build BPB
-
- ; return BPB address in request header
- mov word ptr es:[di+18],offset bpb
- mov word ptr es:[di+20],cs
-
- xor ax,ax ; set "done" status
- ret
-
- build_bpb endp
-
-
- read proc near ; command code 4 = Read
-
- call init_xfer ; set up local variables
-
- read1: mov ax,xfer_cnt ; done with all sectors yet?
- cmp ax,xfer_req
- je read2 ; jump if transfer completed
- mov ax,xfer_sec ; get next sector number
- call map_sec ; and map it
- jc read4 ; jump if mapping error
- les di,xfer_addr ; ES:DI = requestor's buffer
- mov si,ax ; DS:SI = EMSDISK address
- mov ds,page_frame
- mov cx,sec_size ; transfer logical sector from
- cld ; EMSDISK to requestor
- rep movsb
- push cs ; restore local addressing
- pop ds
- inc xfer_sec ; advance sector number
- ; advance transfer address
- add word ptr xfer_addr,sec_size
- inc xfer_cnt ; count sectors transferred
- jmp read1
-
- read2: ; all sectors successfully
- xor ax,ax ; transferred, return ok status
-
- read3: les di,[rh_ptr] ; get address of Request header
- mov bx,xfer_cnt ; and poke in actual transfer count
- mov es:[di.count],bx ; (in case error aborted transfer
- ret ; early)
-
- read4: ; come here if mapping error deteced
- mov ax,800bh ; return read fault error code
- jmp read3
-
- read endp
-
-
- write proc near ; command code 8 = write
- ; command code 9 = write/verify
-
- call init_xfer ; set up local variables
-
- write1: mov ax,xfer_cnt ; done with all sectors yet?
- cmp ax,xfer_req
- je write2 ; jump if transfer completed
- mov ax,xfer_sec ; get next sector number
- call map_sec ; and map it
- jc write4 ; jump if mapping error detected
- mov di,ax ; ES:DI = EMSDISK address
- mov es,page_frame
- lds si,xfer_addr ; DS:SI = requestor's buffer
- mov cx,sec_size ; transfer logical sector from
- cld ; requestor to EMSDISK
- rep movsb
- push cs ; restore local addressing
- pop ds
- inc xfer_sec ; advance sector number
- ; advance transfer address
- add word ptr xfer_addr,sec_size
- inc xfer_cnt ; count sectors transferred
- jmp write1
-
- write2: ; all sectors successfully
- xor ax,ax ; transferred, return ok status
-
- write3:
- les di,[rh_ptr] ; get address of Request header
- mov bx,xfer_cnt ; and poke in actual transfer count
- mov es:[di.count],bx ; (in case error aborted transfer
- ret ; early)
-
- write4: ; error detected
- mov ax,800ah ; return write fault error code
- jmp write3
-
- write endp
-
-
- dummy proc near ; this command code routine is
- ; called for functions that are
- ; not supported or are applicable
- ; to character devices only.
-
- xor ax,ax ; return success flag for all
- ret
-
- dummy endp
-
- page
-
- ;
- ; Map into memory a logical "disk" sector from the EMS
- ; pages allocated to the EMSDISK.
- ;
- ; Called with: AX = logical sector number
- ;
- ; Returns: CY = clear if no error
- ; AX = offset within EMS page frame
- ; AX,CX,DX destroyed
- ;
- ; CY = set if EMM mapping error
- ; AX,CX,DX destroyed
- ;
- map_sec proc near
-
- mov dx,0 ; divide sector no. by sectors
- mov cx,sec_per_page ; per page, to get EMS page number
- div cx ; now AX=EMS page,DX=rel. sector
- push dx ; save remainder
- mov bx,ax ; BX <- EMS page number
- mov ax,4400h ; map function, phys. page=0
- mov dx,emm_handle ; process ID for EMSDISK
- int 67h
-
- or ah,ah ; if EMM error, jump to return flag
- jnz map_sec1
-
- pop ax ; get remainder (relative sector)
- mov cx,sec_size ; remainder*sec_size to get offset
- mul cx ; into EMS logical page
- clc ; return CY=clear for no error
- ret ; back to caller
-
- map_sec1: ; come here if EMM mapping error
- add sp,2 ; clear stack
- stc ; return CY=set for error
- ret
-
- map_sec endp
-
- ;
- ; Set up to perform Read or Write subfunction by copying
- ; requestor's buffer address, starting sector, and sector
- ; count out of Request header into local variables.
- ;
- init_xfer proc near ; call ES:DI=request header
- ; extracts addr, start, count
- ; to working variables
-
- push es ; save Request header addr
- push di
- ; initialize working variables
- ; for transfer
- mov ax,es:[di.sector]
- mov xfer_sec,ax ; starting sector number
- mov ax,es:[di.count]
- mov xfer_req,ax ; sectors requested
- les di,es:[di.address]
- ; requestor's buffer offset
- mov word ptr xfer_addr,di
- ; requestor's buffer segment
- mov word ptr xfer_addr+2,es
- mov xfer_cnt,0 ; init sectors transferred count
- pop di ; restore Request header addr
- pop es
- ret
-
- init_xfer endp
-
- page
-
- ; The Initialization code for the driver is called only
- ; once when the driver is loaded. For a block device, it
- ; must return the number of units, address of an array of
- ; pointers to BPBs for each unit, and the address of the
- ; first free memory above the driver in the Request Header.
- ; Only MS-DOS services 01-0CH and 30H can be called by the
- ; Initialization function.
- ;
- ; "Init" returns its own address to the DOS as the start of
- ; free memory after the driver, so that the memory occupied
- ; occupied by "init" and its subroutines will be reclaimed.
- ;
- init proc near ; command code 0 = Initialize Driver
- ; on entry ES:DI = request header
-
- les di,es:[di+18] ; get addr of CONFIG.SYS line
- ; and copy it to local buffer
- mov si,offset cmd_line
- mov cx,80 ; CX = max line length to copy
-
- init0: mov al,es:[di] ; get next character of line
- cmp al,cr ; found Carriage Return yet?
- je init1 ; yes, end of line
- mov [si],al ; no, copy this character
- inc di ; bump string pointers
- inc si
- loop init0 ; loop unless 80 characters copied
-
- init1: mov ah,30h ; get DOS version
- int 21h
- mov dos_ver,al ; and major version no. for later
-
- ; set maximum legal command code
- mov max_cmd,cc2_max ; assume DOS 2.X
- cmp al,2
- je init2 ; jump if DOS 2
- mov max_cmd,cc3_max ; was DOS 3+, set higher value
-
- init2: xor ax,ax ; check if EMM driver present
- mov es,ax ; if EMM is present, address in
- mov bx,emm_int*4 ; vector points to EMM driver.
- mov es,es:[bx+2] ; now ES:0000 would point to EMM header
- mov di,10 ; let ES:DI = addr of device name field
- ; let DS:SI = addr of EMM driver name
- mov si,offset emm_name
- mov cx,8 ; length of device name field
- cld
- repz cmpsb ; compare EMM name to driver header.
- jz init3 ; jump if strings matched.
- mov dx,offset msg1 ; if strings didn't match,
- jmp init_err ; driver is absent, exit.
-
- init3: mov ah,40h ; EMM driver module is present,
- int 67h ; test EM Manager status.
- or ah,ah
- jz init4 ; jump, driver is OK
- mov dx,offset msg2 ; EMM is non-functional, print
- jmp init_err ; error message and exit
-
- init4: mov ah,46h ; check EM Manager version
- int 67h
- or ah,ah
- jz init5 ; jump, got version ok
- init45: mov dx,offset msg3 ; print EMM error message
- jmp init_err ; and exit, discarding driver
-
- init5: cmp al,030h ; make sure at least ver. 3.0
- jae init6 ; jump if EMM version adequate
- mov dx,offset msg6
- jmp init_err ; EMM version too early, exit
-
- init6: mov ah,41h ; get page frame segment
- int 67h
- or ah,ah
- jnz init45 ; jump if failed to get frame
- mov page_frame,bx ; save segment of page frame
-
- mov ah,42h ; get number of available pages
- int 67h
- or ah,ah
- jnz init45 ; jump if error on get pages
- mov total_pages,dx ; save total EMM pages
- mov avail_pages,bx ; save available EMM pages
- or bx,bx
- jnz init7 ; proceed if some pages available
- mov dx,offset msg4
- jmp init_err ; no EMS pages left, exit
-
- init7: call get_kb ; convert desired size of EMSDISK
-
- mov ah,43h ; try and allocate EMM pages
- mov bx,owned_pages
- int 67h ; if allocation is successful
- or ah,ah
- jz init8 ; jump, allocation was successful
- mov dx,offset msg5 ; if allocation failed, print
- jmp init_err ; error message and exit
-
- init8: mov emm_handle,dx ; save EMM handle for this driver
-
- call setup ; set up Bios Parameter Block
-
- call format ; format the EMSDISK
- jnc init9 ; jump if no error during format
- mov dx,offset msg7 ; formatting error, exit
- jmp init_err
-
- init9: call signon ; format and display driver ident.
-
- les di,cs:[rh_ptr] ; restore ES:DI=Request header
-
- ; return first usable memory addr.
- ; ("break address") above driver
- mov word ptr es:[di.address],offset init
- mov word ptr es:[di.address+2],cs
-
- ; return EMSDISK logical units = 1
- mov byte ptr es:[di+13],1
-
- ; return address of BPB array
- mov word ptr es:[di+18],offset bpb_array
- mov word ptr es:[di+20],cs
-
- xor ax,ax ; return success status
- ret
-
- init_err: ; EMM initialization failed,
- ; print error message and
- ; discard EMSDISK driver.
-
- push dx ; save specific error message
-
- mov dx,offset ermsg ; print error heading
- mov ah,9
- int 21h
-
- pop dx ; now print error description
- mov ah,9
- int 21h
-
- les di,cs:[rh_ptr] ; restore ES:DI=Request header
-
- ; discard this driver...
-
- ; set break addr=start of driver
- mov word ptr es:[di.address],0
- mov word ptr es:[di.address+2],cs
-
- ; set number of logical units=0
- mov byte ptr es:[di+13],0
-
- xor ax,ax ; return status
- ret
-
- init endp
-
-
- setup proc near ; calculate BPB fields depending
- ; on number of sectors in EMSDISK
-
- mov ax,owned_pages ; find total sectors in EMSDISK,
- mov cx,sec_per_page ; update BIOS parameter block
- mul cx
- mov tot_sec,ax ; store into (word ptr bpb+8)
-
- ; determine number of sectors
- ; per cluster (allocation unit).
- ; must have tot. clusters <4087
- ; so can use 12-bit FAT fields.
-
- mov cx,2 ; start with 2 sectors/cluster
-
- setup1: mov ax,tot_sec ; try this cluster size...
- mov dx,0 ; divide total sectors by
- div cx ; sectors per cluster.
- cmp ax,4086 ; resulting clusters < 4087?
- jna setup2 ; yes, use it
- shl cx,1 ; sec/cluster*2, try again
- jmp setup1
-
- setup2: mov sec_clus,cl ; update sectors per cluster
- ; in Bios Parameter Block
-
- ; now AX = total clusters in disk
- mov dx,ax ; clusters*1.5 = FAT bytes needed
- add ax,ax ; (* 2)
- add ax,dx ; (* 3)
- shr ax,1 ; (/ 2)
-
- mov dx,0 ; FAT bytes needed / bytes/sector
- mov cx,sec_size ; = number of FAT sectors needed
- div cx
- or dx,dx ; any remainder?
- jz setup3 ; no,jump
- inc ax ; round up to next sector
-
- setup3: mov sec_fat,ax ; store number of FAT sectors
- ret ; into (word ptr bpb+0bh)
-
- setup endp
-
-
- format proc near ; format the EMSDISK area
- ; returns CY = clear if successful
- ; CY = set if error
-
- mov bx,0 ; first clear EMSDISK area
-
- fmt1: cmp bx,owned_pages ; done with all EMS pages?
- je fmt2 ; yes, jump
-
- push bx ; save current page number
- mov ax,4400h ; map to physical page 0
- mov dx,emm_handle ; get our process id
- int 67h ; request mapping by EMM
-
- pop bx ; restore page number
- or ah,ah ; if bad mapping give up
- jnz fmt9 ; (should never happen)
-
- mov es,page_frame ; set ES:DI = EMS page
- xor di,di
- mov cx,page_size ; page length
- xor al,al ; fill page with zeros
- cld
- rep stosb
-
- inc bx ; increment page and loop
- jmp fmt1
-
- fmt2: ; copy phony boot sector with
- ; Bios Parameter Block to
- ; EMSDISK's logical sector 0
-
- mov ax,0 ; map in logical sector 0
- call map_sec
- jc fmt9 ; jump if mapping error
- mov di,ax ; let ES:DI = point to sector 0
- mov es,page_frame
- ; let DS:SI point to boot rec.
- mov si,offset boot_rec
- mov cx,boot_rec_len ; CX = length to copy
- rep movsb ; now transfer boot sector
-
- mov ax,1 ; map in EMSDISK logical
- call map_sec ; sector 1 (first sec of FAT)
- jc fmt9 ; jump if mapping error
- mov di,ax
- mov es,page_frame ; ES:DI points to sector 1
-
- ; put media descriptor into FAT
- ; byte 0, bytes 1-2 must be -1
- mov al,byte ptr [bpb+0ah]
- mov es:[di],al
- mov word ptr es:[di+1],-1
-
- ; now set up EMSDISK volume label.
- ; first directory sector=
- ; number of FATs*length of FAT
- ; plus no. of reserved sectors
- mov al,byte ptr [bpb+5]
- xor ah,ah
- mul word ptr [bpb+0bh]
- add ax,word ptr [bpb+3]
- call map_sec ; map in first directory block
- jc fmt9 ; jump if mapping error
- mov di,ax ; copy volume label to directory
- mov es,page_frame
- mov si,offset vol_name
- mov cx,vol_name_len
- rep movsb
-
- clc ; CY = clear, format successful
- ret
-
- fmt9: stc ; CY = set if error during format
- ret
-
- format endp
-
-
- get_kb proc near ; get desired size of EMSDISK
- ; in Kbytes from CONFIG.SYS line,
- ; sets "req_pages" and "owned_pages".
- ; if no disk size requested by user,
- ; makes largest possible EMSDISK.
-
- mov si,offset cmd_line
-
- getkb1: lodsb ; scan for end of driver name
- or al,al ; if zero, no Kbytes requested
- jz getkb9
- cmp al,blank ; if blank, reached end of name
- jne getkb1
-
- getkb2: lodsb ; scan for start of Kbytes field
- or al,al ; if zero found, no Kbytes requested
- jz getkb9
- cmp al,blank ; if blank, keep searching
- je getkb2
-
- dec si ; point to start of field and
- call ascbin ; convert string to binary Kbytes
- or ax,ax ; if request=0, make big disk
- jz getkb9
- mov dx,ax ; save copy of Kbytes
- mov cx,4 ; divide Kbytes by 16 to get
- shr ax,cl ; requested EMS pages
- and dx,0fh ; round up needed?
- jz getkb3 ; jump if multiple of 16 Kbytes
- inc ax
-
- getkb3: mov req_pages,ax ; save requested EMS pages
- cmp ax,avail_pages ; compare with pages available
- jna getkb4 ; jump if ok
- mov ax,avail_pages ; request too large, use avail. only
-
- getkb4: mov owned_pages,ax ; set total EMS pages to allocate
- ret
-
- getkb9: mov ax,avail_pages ; no size requested by user, set
- mov req_pages,ax ; requested and owned to maximum possible.
- mov owned_pages,ax
- ret
-
- get_kb endp
-
-
- signon proc near ; format and print driver ident.
-
- les di,[rh_ptr] ; let ES:DI = Request Header.
- mov al,es:[di+22] ; get drive code from header,
- add al,'A' ; convert it to ASCII, and
- mov drv_code,al ; store into sign-on message
-
- mov ax,cs ; convert load address to ASCII
- mov bx,offset dh_addr
- call hexasc
-
- mov ax,total_pages ; format Kbytes of EM installed
- mov dx,16
- mul dx ; pages * 16 = Kbytes
- mov cx,10
- mov si,offset kb_installed+3
- call binasc ; convert Kbytes to ASCII
-
- mov ax,avail_pages ; format Kbytes of EM available
- mov dx,16
- mul dx ; pages * 16 = Kbytes
- mov cx,10
- mov si,offset kb_avail+3
- call binasc ; convert Kbytes to ASCII
-
- mov ax,owned_pages ; format Kbytes assigned to EMSDISK
- mov dx,16
- mul dx ; pages * 16 = Kbytes
- mov cx,10
- mov si,offset kb_assigned+3
- call binasc ; convert Kbytes to ASCII
-
- mov ah,9 ; print sign-on message
- mov dx,offset ident ; and copyright notice
- int 21h
-
- mov dx,offset dos2m ; check DOS version, if
- cmp dos_ver,2 ; DOS 2 can't know drive letter
- je signon1
- mov dx,offset dos3m ; if DOS 3 can display drive
- signon1:
- mov ah,9 ; print load address, bytes
- int 21h ; in EMSDISK, etc.
-
- ret ; back to caller
-
- signon endp
-
-
- ident db cr,lf,lf
- db 'Expanded Memory EMSDISK 1.0'
- db cr,lf
- db 'Copyright (C) 1986 Ray Duncan'
- db cr,lf,lf,eom
- dos3m db 'EMSDISK will be drive '
- drv_code db 'X:'
- db cr,lf
- dos2m db 'Device driver loaded at '
- dh_addr db 'XXXX:0000'
- db cr,lf,lf
- kb_installed db ' Kbytes Expanded Memory installed.'
- db cr,lf
- kb_avail db ' Kbytes Expanded Memory available.'
- db cr,lf
- kb_assigned db ' Kbytes assigned to EMSDISK.'
- db cr,lf,eom
-
- emm_name db 'EMMXXXX0',0 ; device name for Expanded
- ; Memory Manager
-
- ermsg db cr,lf
- db 'EMS RAMDISK installation error:'
- db cr,lf,eom
-
- msg1 db 'Expanded Memory Manager not found.'
- db cr,lf,eom
-
- msg2 db 'Expanded Memory not functional.'
- db cr,lf,eom
-
- msg3 db 'Expanded Memory Manager error.'
- db cr,lf,eom
-
- msg4 db 'No Expanded Memory pages available.'
- db cr,lf,eom
-
- msg5 db 'Expanded Memory allocation failed.'
- db cr,lf,eom
-
- msg6 db 'Wrong Expanded Memory Manager version.'
- db cr,lf,eom
-
- msg7 db 'Unable to format EMSDISK.'
- db cr,lf,eom
-
- ; phony volume label, copied to
- ; EMSDISK's first directory sector
- vol_name db 'EMS_RAMDISK'
- db 08h ; volume label attribute byte
- db 10 dup (0)
- dw 0 ; time
- dw 0cb0h ; date = May 16, 1986
- db 6 dup (0)
-
- vol_name_len equ $-vol_name
-
-
- page
-
- ; HEXASC: convert a binary 16-bit number into
- ; a "hexadecimal" ASCII string.
- ;
- ; Call with AX = value to convert
- ; DS:BX = address to store 4-character string
- ;
- ; Returns AX, BX destroyed, other registers preserved
- ;
- hexasc proc near
-
- push cx ; save registers
- push dx
-
- mov dx,4 ; initialize character counter
-
- hexasc1:
- mov cx,4 ; isolate next four bits
- rol ax,cl
- mov cx,ax
- and cx,0fh
- add cx,'0' ; convert to ASCII
- cmp cx,'9' ; is it 0-9?
- jbe hexasc2 ; yes, jump
- add cx,'A'-'9'-1 ; add fudge factor for A-F
-
- hexasc2: ; store this character
- mov [bx],cl
- inc bx ; bump string pointer
-
- dec dx ; count characters converted
- jnz hexasc1 ; loop, not four yet
-
- pop dx ; restore registers
- pop cx
- ret ; back to caller
-
- hexasc endp
-
- ;
- ; BINASC: Convert 32 bit binary value to ASCII string.
- ;
- ; Call with DX:AX = signed 32 bit value
- ; CX = radix
- ; SI = last byte of area to store resulting string
- ; (make sure enough room is available to store
- ; the string in the radix you have selected.)
- ;
- ; Destroys AX, BX, CX, DX, and SI.
- ;
- binasc proc near ; convert DX:AX to ASCII.
-
- ; force storage of at least 1 digit.
- mov byte ptr [si],'0'
- or dx,dx ; test sign of 32 bit value,
- pushf ; and save sign on stack.
- jns bin1 ; jump if it was positive.
- not dx ; it was negative, take 2's complement
- not ax ; of the value.
- add ax,1
- adc dx,0
- bin1: ; divide the 32 bit value by the radix
- ; to extract the next digit for the
- ; forming string.
- mov bx,ax ; is the value zero yet?
- or bx,dx
- jz bin3 ; yes, we are done converting.
- call divide ; no, divide by radix.
- add bl,'0' ; convert the remainder to an ASCII digit.
- cmp bl,'9' ; we might be converting to hex ASCII,
- jle bin2 ; jump if in range 0-9,
- add bl,'A'-'9'-1 ; correct it if in range A-F.
- bin2: mov [si],bl ; store this character into string.
- dec si ; back up through string,
- jmp bin1 ; and do it again.
- bin3: ; restore sign flag,
- popf ; was original value negative?
- jns bin4 ; no, jump
- ; yes,store sign into output string.
- mov byte ptr [si],'-'
- bin4: ret ; back to caller.
-
- binasc endp
-
- ;
- ; General purpose 32 bit by 16 bit unsigned divide.
- ; This must be used instead of the plain machine unsigned divide
- ; for cases where the quotient may overflow 16 bits (for example,
- ; dividing 100,000 by 2). If called with a zero divisor, this
- ; routine returns the dividend unchanged and gives no warning.
- ;
- ; Call with DX:AX = 32 bit dividend
- ; CX = divisor
- ;
- ; Returns DX:AX = quotient
- ; BX = remainder
- ; CX = divisor (unchanged)
- ;
- divide proc near ; Divide DX:AX by CX
-
- jcxz div1 ; exit if divide by zero
- push ax ; 0:dividend_upper/divisor
- mov ax,dx
- xor dx,dx
- div cx
- mov bx,ax ; BX = quotient1
- pop ax ; remainder1:dividend_lower/divisor
- div cx
- xchg bx,dx ; DX:AX = quotient1:quotient2
-
- div1: ret ; BX = remainder2
-
- divide endp
-
- ;
- ; ASCBIN: Convert decimal ASCII string to unsigned binary integer.
- ; Conversion ends on first byte not {'0'...'9'}.
- ;
- ; Call with DS:SI = addr of ASCII string
- ;
- ; Returns AX = unsigned binary integer
- ; DS:SI points to unconvertable character + 1
- ;
- ascbin proc near
-
- push dx ; save prev. register contents
- xor dx,dx ; set forming answer to zero
- ascbin1:
- lodsb ; get next character from input string.
- cmp al,'9' ; make sure it is legal character 0-9.
- ja ascbin2 ; char > '9', exit with error flag.
- cmp al,'0'
- jb ascbin2 ; char < '0', exit with error flag.
- push ax ; save character from string
- mov ax,10 ; multiply prev answer * 10
- mul dx ; low part of answer*10 now in AX
- pop dx
- and dx,0fh ; isolate binary value 0-9
- add dx,ax ; accumulate forming answer
- jmp ascbin1 ; get next character
- ascbin2: ; end of conversion,
- mov ax,dx ; return answer in AX
- pop dx ; and restore register DX.
- ret
-
- ascbin endp
-
-
- code ends
-
- end
- ersion,
- mov ax,dx ; return answer in AX
- pop dx ; and restore register DX.
- ret
-
- asc